﻿/* Copyright 2010 Igor Francé
 * 
 * This file is part of ECMADoc (http://ecmadoc.codeplex.com).
 * 
 * ECMADoc is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * ECMADoc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with ECMADoc. 
 * If not, see http://www.gnu.org/licenses/.
 */
namespace EcmaDoc.Gui.Forms
{
	using System;
	using System.Collections.Generic;
	using System.Drawing;
	using System.IO;
	using System.Windows.Forms;

	using EcmaDoc.Core;
	using EcmaDoc.Core.Configuration;

	using EcmaDoc.Gui.Controls;
	using EcmaDoc.Gui.Properties;

	using Microsoft.WindowsAPICodePack.Taskbar;

	/// <summary>
	/// Provides the layout and interaction logic for the main gui form.
	/// </summary>
	public sealed partial class MainForm : Form
	{
		private const int FilePathIndex = 1;
		private const int FolderExtIndex = 3;
		private const int ExcludePatternsIndex = 4;

		private static LogColors colors;
		private Project currentProject;

		private bool isChanged;
		private bool isProcessing;

		private string lastSelectedPath;
		private string lastStepName;

		private ProcessThread processThread;
		private long ticksAtStart;

		/// <summary>
		/// Initializes a new instance of the <see cref="MainForm"/> class.
		/// </summary>
		public MainForm()
		{
			this.Font = SystemFonts.MessageBoxFont;

			this.InitializeComponent();
			this.InitializeForm();

			string projectPath = Utilities.ExpandPath("Resources/JavaScript.xml");

			try
			{
				this.SetProject(Project.Create(projectPath));
			}
			catch (Exception ex)
			{
				Log.WriteLine(LogCategory.Error, ex.Message);
				Log.WriteLine(LogCategory.Error, ex.StackTrace);

				LogLine(LogCategory.Error, ex.Message);
			}

			#if DEBUG
			RegenerateButton.Text = "Regenerate";
			#endif
		}

		private static LogColors Colors
		{
			get
			{
				return colors ?? (colors = new LogColors());
			}
		}

		private bool IsProcessing
		{
			get
			{
				return this.HasProject && this.isProcessing;
			}
			
			set
			{
				isProcessing = value;
			}
		}

		private bool IsChanged
		{
			get
			{
				return this.HasProject && this.isChanged;
			}
			
			set
			{
				if (!isChanged && value)
					this.Text += "*";
				if (isChanged && !value)
					this.Text = this.Text.TrimEnd(new[] { '*' });
				
				isChanged = value;
			}
		}

		private bool IsItemSelected
		{
			get
			{
				if (ProjectFiles.Items.Count == 0)
					return false;

				return ProjectFiles.SelectedItems.Count != 0;
			}
		}

		private bool IsWindows7OrHigher
		{
			get
			{
				return
					(Environment.OSVersion.Version.Major > 6) ||
					(Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1);
			}
		}	

		private bool HasProject
		{
			get
			{
				return currentProject != null;
			}
		}

		private bool HasFiles
		{
			get
			{
				return this.HasProject && 
					(this.ProjectInfo.Files.Count != 0 || this.ProjectInfo.Locations.Count != 0);
			}
		}

		private bool HasBeenGenerated
		{
			get
			{
				if (currentProject == null)
					return false;

				return File.Exists(currentProject.ProjectFilePath);
			}
		}

		private bool HasDocumentationGenerated
		{
			get
			{
				if (HasProject)
					return File.Exists(ProjectInfo.GetProjectFileName(HtmlPageType.Default, true));

				return false;
			}
		}

		private string SelectedPathForAddFileDialog
		{
			get
			{
				if (!string.IsNullOrEmpty(lastSelectedPath))
					return lastSelectedPath;

				string expandedPath = new FileInfo(ProjectInfo.SourcePath).FullName;
				return Path.GetDirectoryName(expandedPath);
			}
		}

		private string FormTitle
		{
			get
			{
				string projectSuffix = HasProject ? string.Concat(": ", ProjectInfo.Name) : string.Empty;
				string changedSuffix = isChanged ? "*" : string.Empty;

				return string.Concat(Resources.EcmaDoc, projectSuffix, changedSuffix);
			}
		}

		private ProjectInfo ProjectInfo
		{
			get
			{
				return currentProject != null ? currentProject.Info : null;
			}
		}

		private void InitializeForm()
		{
			this.InitializeControls();
			this.UpdateControls();

			FileEntryEditor.Enter += OnFileEntryEditorEnter;
			FileEntryEditor.Leave += OnFileEntryEditorLeave;
			FileEntryEditor.Change += OnFileEntryEditorValueChanged;
		}

		private void SetProject(Project project)
		{
			ClearLog();
			LogLine(LogCategory.Info, string.Format("Project '{0}' loaded.", project.Info.Name));

			this.IsChanged = false;
			this.currentProject = project;

			this.ProjectProperties.SelectedObject = ProjectInfo;
			currentProject.ProcessProgress += this.OnProjectProgress;

			this.UpdateControls();
			this.UpdateProjectFiles();
		}

		private void StopProcessing()
		{
			if (!this.IsProcessing)
				return;

			if (IsWindows7OrHigher)
				TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress);

			this.IsProcessing = false;
			try
			{
				this.processThread.Abort();
			}
			catch
			{
			}

			this.UpdateControls();
		}

		private void InitializeControls()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Action(this.InitializeControls));
				return;
			}

			this.Text = this.FormTitle;
			this.StatusActive.Text = Resources.Ready;

			this.StatusOperation.Text = string.Empty;
			this.StatusOperation.Visible = false;
			this.StatusFile.Visible = false;

			this.ProgressStep.Value = 0;
			this.ProgressStep.Visible = false;
			
			this.ProgressOperation.Value = 0;
			this.ProgressOperation.Visible = false;

			this.ProgressFile.Value = 0;
			this.ProgressFile.Visible = false;
		}

		private void UpdateControls()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Action(this.UpdateControls));
				return;
			}

			Text = FormTitle;
			ProjectTitle.Text = currentProject != null ? ProjectInfo.Name : string.Empty;
			ProjectFiles.Enabled = HasProject && !IsProcessing;
			DirectoryRemove.Enabled = IsItemSelected && !IsProcessing;
			DirectoryEdit.Enabled = IsItemSelected && !IsProcessing;
			DirectoryAdd.Enabled = HasProject && !IsProcessing;
			ProjectProperties.Enabled = HasProject && !IsProcessing;
			BuildButton.Enabled = HasFiles && !IsProcessing;
			RegenerateButton.Enabled = HasBeenGenerated && !IsProcessing;
			ViewDocumentationButton.Enabled = HasDocumentationGenerated && !IsProcessing;
			CancelBuildButton.Enabled = IsProcessing;

			NewProjectButton.Enabled = !IsProcessing;
			OpenProjectButton.Enabled = !IsProcessing;
			SaveProjectButton.Enabled = HasProject && !IsProcessing;
			SaveProjectAsButton.Enabled = HasProject && !IsProcessing;
		}

		private void UpdateProjectFiles()
		{
			ProjectFiles.Items.Clear();
			if (currentProject == null)
			{
				return;
			}

			ListViewGroup foldersGroup = ProjectFiles.Groups["Directories"];
			ListViewGroup filesGroup = ProjectFiles.Groups["Files"];

			for (int i = 0; i < ProjectInfo.Locations.Count; i++)
			{
				ListViewItem item = new ListViewItem { Group = foldersGroup, ImageKey = "Folder" };
				item.SubItems.Add(ProjectInfo.Locations[i].Path);
				item.SubItems.Add("Folder");
				item.SubItems.Add(ProjectInfo.Locations[i].Extensions);
				item.SubItems.Add(ProjectInfo.Locations[i].Excludes);
				item.Tag = i;
				ProjectFiles.Items.Add(item);
			}

			for (int i = 0; i < ProjectInfo.Files.Count; i++)
			{
				ListViewItem item = new ListViewItem { Group = filesGroup, ImageKey = "File" };
				item.SubItems.Add(ProjectInfo.Files[i]);
				item.SubItems.Add("File");
				item.SubItems.Add(string.Empty);
				item.SubItems.Add(string.Empty);
				item.Tag = i;
				ProjectFiles.Items.Add(item);
			}
		}

		private void HandleProcessException(Exception e)
		{
			Exception source = e;
			while (source.InnerException != null)
				source = source.InnerException;

			this.StopProcessing();
			this.InitializeControls();
			this.UpdateControls();

			Log.WriteLine(LogCategory.Error, source.Message);
			Log.WriteLine(LogCategory.Error, source.StackTrace);

			this.LogLine(LogCategory.Error, source.Message);
		}

		private void ClearLog()
		{
			this.OutputPane.Text = string.Empty;
		}

		private void CreateNewProject()
		{
			if (CancelIfChanged())
				return;

			SaveDialog.ShowDialog();
			if (!string.IsNullOrEmpty(SaveDialog.FileName))
			{
				string projectPath = SaveDialog.FileName;

				Project newProject = Project.Create();
				newProject.Info.Save(projectPath);

				this.SetProject(newProject);
			}
		}

		private void OpenProject()
		{
			if (CancelIfChanged())
				return;

			OpenDialog.ShowDialog();
			if (!string.IsNullOrEmpty(OpenDialog.FileName))
			{
				try
				{
					Project proj = Project.Create(OpenDialog.FileName);
					this.SetProject(proj);
				}
				catch (Exception e)
				{
					LogLine(LogCategory.Fatal, e.Message);
				}
			}
		}

		private void SaveProject(bool promptForName)
		{
			string projectPath = ProjectInfo.SourcePath;
			if (ProjectInfo.SourcePath == null || promptForName)
			{
				DialogResult result = SaveDialog.ShowDialog();
				if (result == DialogResult.Cancel)
					return;

				if (!string.IsNullOrEmpty(SaveDialog.FileName))
				{
					projectPath = SaveDialog.FileName;
				}
			}

			if (!string.IsNullOrEmpty(projectPath))
			{
				this.ProjectInfo.Save(projectPath);
				this.UpdateProjectFiles();
				this.IsChanged = false;
			}
		}

		private void ProcessProject()
		{
			if (string.IsNullOrEmpty(ProjectInfo.OutputPath))
			{
				LogLine(LogCategory.Error, Resources.NoOutputPathSpecified);
				SetPropertyFocus("Output path");
				return;
			}

			ExecuteProjectOperation("Process project");
		}

		private void RegenerateOutput()
		{
			ExecuteProjectOperation("Regenerate output");
		}

		private void ExecuteProjectOperation(string name)
		{
			StartTimer();

			this.processThread = new ProcessThread(() => 
				currentProject.ExecuteOperation(name), this.HandleProcessException);

			this.processThread.Start();

			this.IsProcessing = true;
			this.UpdateControls();
			this.ClearLog();
		}

		private void AddFileEntry()
		{
			FileFolderBrowseDialog dialog = new FileFolderBrowseDialog
				{
					Description = "Select a file or folder to add to current project",
					ShowNewFolderButton = true,
					ShowEditBox = true,
					ShowFullPathInEditBox = true,
					ShowBothFilesAndFolders = true,
					RootFolder = Environment.SpecialFolder.MyComputer,
					SelectedPath = this.SelectedPathForAddFileDialog
				};

			DialogResult result = dialog.ShowDialog();
			if (result == DialogResult.OK)
			{
				if (Directory.Exists(dialog.SelectedPath))
				{
					lastSelectedPath = dialog.SelectedPath;
					IsChanged = ProjectInfo.AddLocation(dialog.SelectedPath);
				}
				else if (File.Exists(dialog.SelectedPath))
				{
					lastSelectedPath = Path.GetDirectoryName(dialog.SelectedPath);
					IsChanged = ProjectInfo.AddFile(dialog.SelectedPath);
				}
				
				this.UpdateProjectFiles();
				this.UpdateControls();
			}
		}

		private void RemoveFileEntry()
		{
			foreach (ListViewItem item in ProjectFiles.SelectedItems)
			{
				string path = item.SubItems[1].Text;
				if (ProjectInfo.Locations.Contains(path))
				{
					ProjectInfo.Locations.Remove(path);
					IsChanged = true;
				}
				else if (ProjectInfo.Files.Contains(path))
				{
					ProjectInfo.Files.Remove(path);
					IsChanged = true;
				}
			}
			
			this.UpdateProjectFiles();
			this.UpdateControls();
		}

		private void EditFilePath()
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			ListViewItem.ListViewSubItem filePath = selected.SubItems[FilePathIndex];

			bool isDirectory = selected.Group.Name == "Directories";

			int startTop = ProjectFiles.Top;
			int startLeft = ProjectFiles.Left;

			FileEntryEditor.Top = startTop + filePath.Bounds.Top;
			FileEntryEditor.Left = startLeft + filePath.Bounds.Left;
			FileEntryEditor.Width = filePath.Bounds.Width;

			FileEntryEditor.Show(filePath.Text, isDirectory);
			FileEntryEditor.Focus();
		}

		private void EditFolderExtension()
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			ListViewItem.ListViewSubItem folderExt = selected.SubItems[FolderExtIndex];

			if (selected.Group.Name != "Directories")
				return;

			int startTop = ProjectFiles.Top;
			int startLeft = ProjectFiles.Left;

			FolderExtEditor.Top = startTop + folderExt.Bounds.Top + 2;
			FolderExtEditor.Left = startLeft + folderExt.Bounds.Left + 5;
			FolderExtEditor.Width = folderExt.Bounds.Width - 4;

			FolderExtEditor.Visible = true;
			FolderExtEditor.Text = folderExt.Text;
			FolderExtEditor.Focus();
			FolderExtEditor.SelectAll();
		}

		private void EditExcludePatterns()
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			ListViewItem.ListViewSubItem excludePatterns = selected.SubItems[ExcludePatternsIndex];

			if (selected.Group.Name != "Directories")
				return;

			int startTop = ProjectFiles.Top;
			int startLeft = ProjectFiles.Left;

			ExcludePatternsEditor.Top = startTop + excludePatterns.Bounds.Top + 2;
			ExcludePatternsEditor.Left = startLeft + excludePatterns.Bounds.Left + 5;
			ExcludePatternsEditor.Width = excludePatterns.Bounds.Width - 4;

			ExcludePatternsEditor.Visible = true;
			ExcludePatternsEditor.Text = excludePatterns.Text;
			ExcludePatternsEditor.Focus();
			ExcludePatternsEditor.SelectAll();
		}

		private void SetPropertyFocus(string propName)
		{
			GridItem selected = ProjectProperties.SelectedGridItem;
			if (selected != null)
			{
				foreach (GridItem item in selected.Parent.GridItems)
				{
					if (item.Label == propName)
					{
						ProjectProperties.Focus();
						item.Select();
						break;
					}
				}
			}
		}

		private void LogLine(LogCategory category, string message)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Action<LogCategory, string>(this.LogLine), category, message);
				return;
			}

			if (string.IsNullOrEmpty(message))
				return;

			// color text.
			OutputPane.SelectionStart = OutputPane.Text.Length;
			OutputPane.SelectionColor = Colors[category];

			// newline if first line, append if else.
			if (OutputPane.Lines.Length == 0)
			{
				OutputPane.AppendText(message);
				OutputPane.ScrollToCaret();
				OutputPane.AppendText(Environment.NewLine);
			}
			else
			{
				OutputPane.AppendText(message + Environment.NewLine);
				OutputPane.ScrollToCaret();
			}
		}

		private bool CancelIfChanged()
		{
			if (IsChanged)
			{
				DialogResult result = MessageBox.Show(Resources.ConfirmSaveChanges, Resources.EcmaDoc, MessageBoxButtons.YesNoCancel);
				if (result == DialogResult.Cancel)
					return true;
				if (result == DialogResult.Yes)
					SaveProject(false);
			}
			
			return false;
		}

		private void StartTimer()
		{
			ticksAtStart = DateTime.Now.Ticks;
		}

		private void UpdateFileEntryValue(TextBox source)
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			int entryIndex = (int) selected.Tag;

			if (source == FolderExtEditor)
			{
				ListViewItem.ListViewSubItem folderExt = selected.SubItems[FolderExtIndex];
				folderExt.Text = FolderExtEditor.Text;
				if (ProjectInfo.Locations[entryIndex].Extensions != folderExt.Text)
				{
					string oldValue = ProjectInfo.Locations[entryIndex].Extensions;

					try
					{
						ProjectInfo.Locations[entryIndex].Extensions = folderExt.Text;
						IsChanged = true;
					}
					catch (Exception ex)
					{
						LogLine(LogCategory.Warning, string.Format("Cannot set folder extensions to '{0}'", folderExt.Text));
						LogLine(LogCategory.Error, ex.Message);
						
						ProjectInfo.Locations[entryIndex].Extensions = folderExt.Text = oldValue;
					}
				}
			}
			else
			{
				ListViewItem.ListViewSubItem excludePatters = selected.SubItems[ExcludePatternsIndex];
				excludePatters.Text = ExcludePatternsEditor.Text;
				if (ProjectInfo.Locations[entryIndex].Excludes != excludePatters.Text)
				{
					string oldValue = ProjectInfo.Locations[entryIndex].Excludes;

					try
					{
						ProjectInfo.Locations[entryIndex].Excludes = excludePatters.Text;
						IsChanged = true;
					}
					catch (Exception ex)
					{
						LogLine(LogCategory.Warning, string.Format("Cannot set exclude patterns to '{0}'", excludePatters.Text));
						LogLine(LogCategory.Error, ex.Message);

						ProjectInfo.Locations[entryIndex].Excludes = excludePatters.Text = oldValue;
					}
				}
			}
		}

		private void OnProjectProgress(object sender, ProjectOperationProgressEventArgs e)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Action<object, ProjectOperationProgressEventArgs>(this.OnProjectProgress), sender, e);
				return;
			}

			if (e.Complete)
			{
				TimeSpan i = new TimeSpan(DateTime.Now.Ticks - ticksAtStart);
				int minutes = i.Minutes;
				
				double seconds = (i.TotalMilliseconds - (i.Hours * 3600000) - (i.Minutes * 60000)) / 1000;
				string message = minutes != 0
					? string.Format("Time taken: {0}min {1}sec", minutes, seconds.ToString("00"))
					: string.Format("Time taken: {0}sec", seconds.ToString("00.00"));

				LogLine(LogCategory.Info, message);

				if (IsWindows7OrHigher)
					TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress);

				this.processThread = null;

				this.IsProcessing = false;
				this.UpdateControls();

				this.InitializeControls();
			}
			else
			{
				if (IsWindows7OrHigher)
				{
					TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal);
					TaskbarManager.Instance.SetProgressValue(e.PercentDoneOperationTotal, 100);
				}

				this.IsProcessing = true;
				this.UpdateControls();

				this.StatusFile.Text = e.ObjectName;
				this.StatusOperation.Text =
					string.Format(Resources.ProcessingOperation, e.CurrentStepName, e.StepNumber, e.StepCount);
				this.StatusActive.Text = e.OperationName;

				this.ProgressFile.Value = e.PercentDoneCurrentFile;
				this.ProgressStep.Value = e.PercentDoneOperationStep;
				this.ProgressOperation.Value = e.PercentDoneOperationTotal;

				this.ProgressOperation.Visible = true;

				this.StatusFile.Visible = true;
				this.StatusOperation.Visible = true;

				if (e.CurrentStepName != lastStepName)
					LogLine(LogCategory.Debug, e.CurrentStepName);

				lastStepName = e.CurrentStepName;
			}
		}

		private void OnProcessButtonClick(object sender, EventArgs e)
		{
			this.ProcessProject();
		}

		private void OnReGenerateOutputClick(object sender, EventArgs e)
		{
			RegenerateOutput();
		}

		private void OnStopButtonClick(object sender, EventArgs e)
		{
			this.StopProcessing();
		}

		private void OnClosing(object sender, FormClosingEventArgs e)
		{
			if (this.processThread != null)
			{
				this.processThread.Abort();
				this.processThread = null;
			}

			if (CancelIfChanged())
				e.Cancel = true;
		}

		private void OnExitMenuClick(object sender, EventArgs e)
		{
			this.Close();
		}

		private void OnAboutMenuClick(object sender, EventArgs e)
		{
			new AboutForm().ShowDialog();
		}

		private void OnNewProjectClick(object sender, EventArgs e)
		{
			CreateNewProject();
		}

		private void OnOpenProjectClick(object sender, EventArgs e)
		{
			OpenProject();
		}

		private void OnSaveProjectClick(object sender, EventArgs e)
		{
			SaveProject(false);
		}

		private void OnSaveProjectAsClick(object sender, EventArgs e)
		{
			SaveProject(true);
		}

		private void OnProjectPropertiesValueChanged(object s, PropertyValueChangedEventArgs e)
		{
			IsChanged = true;
			UpdateControls();
		}

		private void OnAddFileClick(object sender, EventArgs e)
		{
			AddFileEntry();
		}

		private void OnRemoveFileClick(object sender, EventArgs e)
		{
			RemoveFileEntry();
		}

		private void OnEditFileClick(object sender, EventArgs e)
		{
			EditFilePath();
		}

		private void OnFileEntryEditorEnter(object sender, EventArgs e)
		{
			FileEntryEditor.Show();
		}

		private void OnFileEntryEditorLeave(object sender, EventArgs e)
		{
			FileEntryEditor.Hide();
		}

		private void OnFileEntryEditorValueChanged(object sender, EventArgs e)
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			if (string.IsNullOrEmpty(FileEntryEditor.FilePath))
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			ListViewItem.ListViewSubItem filePath = selected.SubItems[FilePathIndex];

			filePath.Text = FileEntryEditor.FilePath;

			int entryIndex = (int) selected.Tag;
			if (selected.Group.Name == "Directories")
			{
				if (ProjectInfo.Locations[entryIndex].Path != filePath.Text)
				{
					IsChanged = true;
					ProjectInfo.Locations[entryIndex].Path = filePath.Text;
				}
			}
			else
			{
				if (ProjectInfo.Files[entryIndex] != filePath.Text)
				{
					IsChanged = true;
					ProjectInfo.Files[entryIndex] = filePath.Text;
				}
			}
		}

		private void OnProjectFilesSelectedIndexChanged(object sender, EventArgs e)
		{
			UpdateControls();
		}

		private void OnProjectFilesMouseDoubleClick(object sender, MouseEventArgs e)
		{
			if (ProjectFiles.SelectedItems.Count == 0)
				return;

			ListViewItem selected = ProjectFiles.SelectedItems[0];
			int subItemIndex = -1;

			int offsetLeft = 0;
			for (int i = 0; i < selected.SubItems.Count; i++)
			{
				ListViewItem.ListViewSubItem item = selected.SubItems[i];

				int minX = offsetLeft;
				int minY = item.Bounds.Top;
				int maxX = minX + ProjectFiles.Columns[i].Width;
				int maxY = minY + item.Bounds.Height;

				if (e.X >= minX && e.X <= maxX && e.Y >= minY && e.Y <= maxY)
				{
					subItemIndex = i;
					break;
				}

				offsetLeft += ProjectFiles.Columns[i].Width;
			}

			if (subItemIndex == FilePathIndex)
				EditFilePath();

			if (subItemIndex == FolderExtIndex)
				EditFolderExtension();

			if (subItemIndex == ExcludePatternsIndex)
				EditExcludePatterns();
		}

		private void OnProjectFilesColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
		{
			FileEntryEditor.Hide();
			FolderExtEditor.Hide();
		}

		private void OnMainFormResizeBegin(object sender, EventArgs e)
		{
			FileEntryEditor.Hide();
			FolderExtEditor.Hide();
		}

		private void OnOverlayTextboxLeave(object sender, EventArgs e)
		{
			UpdateFileEntryValue((TextBox) sender);
			((TextBox) sender).Hide();
		}

		private void OnOverlayTextboxTextChanged(object sender, EventArgs e)
		{
			UpdateFileEntryValue((TextBox) sender);
		}

		private void OnOverlayTextboxKeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				((TextBox) sender).Hide();
				e.SuppressKeyPress = true;
			}

			if (e.KeyData == Keys.Escape)
			{
				((TextBox) sender).Hide();
				e.SuppressKeyPress = true;
			}
		}

		private void OnViewDocumentationButtonClick(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(ProjectInfo.GetProjectFileName(HtmlPageType.Default, true));
		}

		/// <summary>
		/// Defines the log colors.
		/// </summary>
		private class LogColors : Dictionary<LogCategory, Color>
		{
			/// <summary>
			/// Initializes a new instance of the <see cref="LogColors"/> class.
			/// </summary>
			public LogColors()
			{
				this.Add(LogCategory.Debug, Color.FromArgb(128, 128, 128));
				this.Add(LogCategory.Error, Color.FromArgb(192, 0, 0));
				this.Add(LogCategory.Fatal, Color.FromArgb(255, 0, 0));
				this.Add(LogCategory.Info, Color.FromArgb(0, 0, 0));
				this.Add(LogCategory.Warning, Color.FromArgb(255, 128, 0));
			}
		}
	}
}
